package main

import (
	"time"
	"fmt"
	"context"
	"sync/atomic"
)

func coordinateWithWaitContext() {
	total := 12
	var num int32
	cxt, cancelFunc := context.WithCancel(context.Background())
	// 定义好goroutine中返回前要执行的defer函数，这里用到了上面的cancelFunc
	deferFunc := func() {
		if atomic.LoadInt32(&num) == int32(total) {
			cancelFunc()
		}
	}
	for i := 0; i < total; i++ {
		go addNum(&num, i, deferFunc)
	}
	<- cxt.Done()
}

func addNum(numP *int32, id int, deferFunc func()) {
	defer func() {
		deferFunc()
	}()
	for i := 1; ; i++ {
		currNum := atomic.LoadInt32(numP)
		newNum := currNum + 1
		time.Sleep(time.Millisecond * 200)
		if atomic.CompareAndSwapInt32(numP, currNum, newNum) {
			fmt.Printf("id: %02d 第 %02d 次更新num成功: %d\n", id, i, newNum)
			break
		}
	}
}

func main() {
	coordinateWithWaitContext()
}